package com.ocm.core.helper;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jcr.RepositoryException;
import javax.jcr.Value;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


import com.ocm.core.constant.OCMConstant;
import com.ocm.core.domain.ClassDefinition;
import com.ocm.core.domain.ClassDefinitionType;
import com.ocm.core.domain.PropertyDefinition;
import com.ocm.core.domain.PropertyType;
import com.ocm.core.domain.Storage;
import com.ocm.core.dto.UserInfoDto;
import com.ocm.core.exception.OCMRuntimeException;
import com.ocm.core.exception.UnsupportTypeException;
import com.ocm.core.service.SecurityService;
import com.ocm.core.util.DateUtil;
import com.ocm.core.util.OCMUtil;
import com.ocm.core.util.XMLUtil;

@Component
public class StorageHelper {

   private static final Log LOG = LogFactory.getLog(StorageHelper.class);

   @Autowired
   private SecurityService securityService;

   public List<ClassDefinition> getClassDefsDefault(Storage storage) {
      List<ClassDefinition> classDefsDefault = new ArrayList<ClassDefinition>();
      try {
         ClassPathResource classPathResource = new ClassPathResource("/SystemStorage.xml");
         Document doc = XMLUtil.createDocument(classPathResource.getInputStream());
         NodeList nodeList = doc.getElementsByTagName("classDef");
         for (int index = 0; index < nodeList.getLength(); index++) {
            Node node = nodeList.item(index);
            ClassDefinition classDef = new ClassDefinition();
            classDef.setName(node.getAttributes().getNamedItem("name").getNodeValue());
            classDef.setDisplayName(node.getAttributes().getNamedItem("displayName").getNodeValue());
            classDef.setClassDefinitionType(ClassDefinitionType.getClassDefType(Integer.parseInt(node.getAttributes()
                  .getNamedItem("classDefinitionType").getNodeValue())));
            classDef.setClassDefUID(node.getAttributes().getNamedItem("uid").getNodeValue());
            classDef.setRealPath(node.getAttributes().getNamedItem("realPath").getNodeValue());
            classDef.setDescription(node.getAttributes().getNamedItem("description").getNodeValue());
            classDef.setStorage(storage);
            classDefsDefault.add(classDef);
         }
         List<PropertyDefinition> propertyDefs = new ArrayList<PropertyDefinition>();
         NodeList propertiesList = doc.getElementsByTagName("propertyDef");
         for (int index = 0; index < propertiesList.getLength(); index++) {
            Node node = propertiesList.item(index);
            PropertyDefinition propertyDefinition = new PropertyDefinition();
            propertyDefinition.setDescription(node.getAttributes().getNamedItem("description").getNodeValue());
            propertyDefinition.setDisplayName(node.getAttributes().getNamedItem("displayName").getNodeValue());
            propertyDefinition.setMaxlength(Integer.parseInt(node.getAttributes().getNamedItem("maxlength")
                  .getNodeValue()));
            propertyDefinition.setMultiValue(Boolean.parseBoolean(node.getAttributes().getNamedItem("description")
                  .getNodeValue()));
            propertyDefinition.setName(node.getAttributes().getNamedItem("name").getNodeValue());
            propertyDefinition.setPropertyType(PropertyType.getPropertyType(Integer.parseInt(node.getAttributes()
                  .getNamedItem("propertyType").getNodeValue())));
            propertyDefinition.setIsHidden(Boolean.parseBoolean(node.getAttributes().getNamedItem("isHidden")
                  .getNodeValue()));
            propertyDefinition.setReadOnly(Boolean.parseBoolean(node.getAttributes().getNamedItem("readOnly")
                  .getNodeValue()));
            Node defaultValueNode = node.getAttributes().getNamedItem("defaultValue");
            propertyDefinition.setDefaultValue(defaultValueNode==null?null:defaultValueNode.getNodeValue());
            propertyDefinition.setStorage(storage);
            this.setUserInfo(propertyDefinition);
            propertyDefs.add(propertyDefinition);
         }
         storage.setPropertyDefs(propertyDefs);
         NodeList relationship = doc.getElementsByTagName("classDef_propertyDef");
         for (int index = 0; index < relationship.getLength(); index++) {
            Node node = relationship.item(index);
            String classDefName = node.getAttributes().getNamedItem("classDefName").getNodeValue();
            String propertyName = node.getAttributes().getNamedItem("propertyDefName").getNodeValue();
            ClassDefinition classDefinition = OCMUtil.getClassDefinition(classDefName, classDefsDefault);
            PropertyDefinition propertyDefinition = OCMUtil.getPropertyDefinition(propertyName, propertyDefs);
            List<PropertyDefinition> properties = classDefinition.getPropertyDefs();
            properties.add(propertyDefinition);
            classDefinition.setPropertyDefs(properties);
         }
      }
      catch (Exception e) {
         LOG.equals(e);
         throw new OCMRuntimeException(e);
      }
      return classDefsDefault;
   }

   public void setUserInfo(Storage domain){
      Date currentDate = DateUtil.getCurrentDate();
      UserInfoDto userInfoDto = this.securityService.getCurrentUsername();
      String currentUser = userInfoDto.getUsername();
      if (domain.getId() == null || domain.getId() == 0){
         domain.setCreatedDated(currentDate);
         domain.setCreatedUser(currentUser);
      }
      domain.setModifyedDated(currentDate);
      domain.setModifyedUser(currentUser);
   }
   
   public void setUserInfo(ClassDefinition domain){
      Date currentDate = DateUtil.getCurrentDate();
      UserInfoDto userInfoDto = this.securityService.getCurrentUsername();
      String currentUser = userInfoDto.getUsername();
      if (domain.getId() == null || domain.getId() == 0){
         domain.setCreatedDated(currentDate);
         domain.setCreatedUser(currentUser);
      }
      domain.setModifyedDated(currentDate);
      domain.setModifyedUser(currentUser);
   }

   public void setUserInfo(PropertyDefinition domain){
      Date currentDate = DateUtil.getCurrentDate();
      UserInfoDto userInfoDto = this.securityService.getCurrentUsername();
      String currentUser = userInfoDto.getUsername();
      if (domain.getId() == null || domain.getId() == 0){
         domain.setCreatedDated(currentDate);
         domain.setCreatedUser(currentUser);
      }
      domain.setModifyedDated(currentDate);
      domain.setModifyedUser(currentUser);
   }

   public Map<PropertyDefinition, Value> getUserInfo (List<PropertyDefinition> properties, ClassDefinition classDefinition) throws UnsupportTypeException, RepositoryException{
      Map<PropertyDefinition, Value> propertyMaps = new HashMap<PropertyDefinition, Value>();
      PropertyDefinition propertyDefinition = OCMUtil.getPropertyDefinition(OCMConstant.CREATED_USER, properties);
      propertyMaps.put(propertyDefinition, propertyDefinition.getPropertyType().convertValue(classDefinition.getCreatedUser()));
      
      propertyDefinition = OCMUtil.getPropertyDefinition(OCMConstant.CREATED_DATED, properties);
      propertyMaps.put(propertyDefinition, propertyDefinition.getPropertyType().convertValue(classDefinition.getCreatedDated()));
      
      propertyDefinition = OCMUtil.getPropertyDefinition(OCMConstant.MODIFYED_USER, properties);
      propertyMaps.put(propertyDefinition, propertyDefinition.getPropertyType().convertValue(classDefinition.getModifyedUser()));
      
      propertyDefinition = OCMUtil.getPropertyDefinition(OCMConstant.MODIFYED_DATE, properties);
      propertyMaps.put(propertyDefinition, propertyDefinition.getPropertyType().convertValue(classDefinition.getModifyedDated()));
      return propertyMaps;
   }
}